import java.awt.Graphics;
import java.awt.image.ImageObserver;
import java.util.ArrayList;

/**
 * Helper class to update all of the projectiles in the game.
 * @author Chris
 *
 */
public class ProjectileControl {
	static ArrayList<Projectile> lasers;
	static Defender defender;
	
	public enum Owner{DEFENDER, INVADERS};
	
	private boolean projectilesCollide;
	
	ProjectileControl(Defender def, boolean collisions){
		lasers = new ArrayList<Projectile>();
		defender = def;
		projectilesCollide = collisions;
	}
	
	/**
	 * Updates all projectiles, performs collision detections, metes consequences
	 * @param wave
	 * @param bases
	 */
	public void update(Wave wave, ArrayList<Base> bases){

		// extract ArrayList of invaders
		ArrayList<Invader> invaders = wave.getInvaders();
		Bonus bonus = wave.getBonus();
		
		// prune out any spent projectiles from before.
		ArrayList<Projectile> laserCopies = new ArrayList<Projectile>();
		laserCopies.addAll(lasers);
		lasers.clear();
		
		// weed out spent projectiles for garbage collection
		for(Projectile projectile:laserCopies){
			if(!projectile.isSpent()){
				lasers.add(projectile);
			}
		}
		
		// update all projectiles in the game
		for(Projectile projectile:lasers){
			projectile.update();
		}
		
		// check for collisions between Defender and Invader lasers.
		if(projectilesCollide){
			for(Projectile projectile:lasers){
				for(Projectile other:lasers){
					if(projectile.getRect().intersects(other.getRect()) && !projectile.isSpent() && !other.isSpent() && projectile.getOwner() != other.getOwner()){
						projectile.spend();
						other.spend();
					}
				}
			}
		}
		
		// check laser collisions with non-lasers
		for(Projectile projectile:lasers){
			if(projectile.getOwner() == Owner.DEFENDER){
				// check collisions with Invaders
				for(Invader invader:invaders){
					if(invader.getRect().intersects(projectile.getRect()) && invader.isAlive() && !projectile.isSpent()){
						invader.die();
						projectile.spend();
					}
				}
				// check collisions with bases
				for(Base base:bases){
					if(base.getRect().intersects(projectile.getRect()) && !projectile.isSpent()){
						projectile.spend();
						base.takeDamage();
					}
				}
				if(bonus != null){
					if(bonus.getRect().intersects(projectile.getRect()) && bonus.isAlive() && !projectile.isSpent()){
						bonus.die();
						projectile.spend();
					}
				}
			}
			else{
				// check collisions with Defender/bases
				for(Base base:bases){
					if(base.getRect().intersects(projectile.getRect()) && !projectile.isSpent()){
						projectile.spend();
						base.takeDamage();
					}
				}
				if(defender.getRect().intersects(projectile.getRect()) && !defender.isDead() && !projectile.isSpent()){
					defender.die();
					projectile.spend();
				}
			}
		}
	}
	
	/**
	 * Returns a list of the currently-active projectiles
	 * 
	 * Called by AI scripts to enable laser-dodging
	 * 
	 *  TODO: is there a way to return a list that, when modified, will not change the game state?
	 * 
	 */
	static public ArrayList<Projectile> getProjectiles(){
		return lasers;
	}
	
	static public void addProjectile(int x, int y, Sprite sprite, int velocity){
		Owner owner;
		if(velocity > 0){
			owner = Owner.INVADERS;
		}
		else {owner = Owner.DEFENDER;}
		lasers.add(new Projectile(x, y, velocity, sprite, owner));
	}
	
	public void clear(){
		lasers.clear();
	}
	
	void draw(Graphics g, ImageObserver io){
		for(Projectile p:lasers){
			p.draw(g, io);
		}
	}
	
	static public void say(String msg){
		System.out.println(msg);
	}
}
